{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "StyleGAN2-ADA-PT-AudioReactive-Pitch",
      "provenance": [],
      "collapsed_sections": [],
      "toc_visible": true,
      "machine_shape": "hm",
      "authorship_tag": "ABX9TyNgKZTMo/vrJmyoXLzolnjy",
      "include_colab_link": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "accelerator": "GPU"
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/dvschultz/stylegan2-ada-pytorch/blob/main/SG2-ADA-PT_AudioReactive%2BPitch.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lC45WUtANxZ8"
      },
      "source": [
        "#StyleGAN2 Reactive Audio\n",
        "\n",
        "By Derrick Schultz for the StyleGAN2 Deep Dive class.\n",
        "\n",
        "This notebook shows one basic example of how to alter your StyleGAN2 vectors with audio. There are lots of different techniques to explore in this, but this is one simple way.\n",
        "\n",
        "Big thanks to Robert Luxemburg who provided the basis for a lot of this code with [this gist](https://gist.github.com/rolux/48f1da6cf2bc6ca5833dbacbf852b348)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "m788lAb7OtJt"
      },
      "source": [
        "##Installation\n",
        "\n",
        "First let’s install the repos and dependencies needed."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "SxwgLpmczcxk",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "94d127c7-371c-4fa0-e1fd-3c71879de131"
      },
      "source": [
        "!nvidia-smi -L"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "GPU 0: Tesla V100-SXM2-16GB (UUID: GPU-769fd161-d896-0474-0c9d-83a26fc88732)\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "5n6wTwbFOofN",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "489b7a00-65e3-435a-eacd-af01e582a6d0"
      },
      "source": [
        "# Derrick's repo (even if you trained with skyflynil this will work!)\n",
        "!git clone https://github.com/dvschultz/stylegan2-ada-pytorch #use this fork to get interpolation functions\n",
        "!pip install ninja opensimplex # needed for noise interpolation\n",
        "%cd stylegan2-ada-pytorch"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Cloning into 'stylegan2-ada-pytorch'...\n",
            "remote: Enumerating objects: 255, done.\u001b[K\n",
            "remote: Counting objects: 100% (9/9), done.\u001b[K\n",
            "remote: Compressing objects: 100% (7/7), done.\u001b[K\n",
            "remote: Total 255 (delta 4), reused 4 (delta 2), pack-reused 246\u001b[K\n",
            "Receiving objects: 100% (255/255), 1.18 MiB | 13.54 MiB/s, done.\n",
            "Resolving deltas: 100% (131/131), done.\n",
            "Collecting ninja\n",
            "\u001b[?25l  Downloading https://files.pythonhosted.org/packages/1d/de/393468f2a37fc2c1dc3a06afc37775e27fde2d16845424141d4da62c686d/ninja-1.10.0.post2-py3-none-manylinux1_x86_64.whl (107kB)\n",
            "\u001b[K     |████████████████████████████████| 112kB 13.4MB/s \n",
            "\u001b[?25hCollecting opensimplex\n",
            "  Downloading https://files.pythonhosted.org/packages/9c/ad/9b758f9ff9dcd23fc574bb3aa1de844adb1179c9be9711e9f798614d4b2f/opensimplex-0.3-py3-none-any.whl\n",
            "Installing collected packages: ninja, opensimplex\n",
            "Successfully installed ninja-1.10.0.post2 opensimplex-0.3\n",
            "/content/stylegan2-ada-pytorch\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FMQbSgmMnDDw"
      },
      "source": [
        "### Import a .pkl file here\n",
        "\n",
        "You can either upload one or use gdown to import one from Google Drive"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "RjLMuFGqPCez",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "2fdcf990-1bd9-4974-d910-0b3a2b79b1cf"
      },
      "source": [
        "!gdown --id 1K7mgdzdQwOERoyft95eFg1-5Tj4XcMAc -O /content/freagan.pkl"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Downloading...\n",
            "From: https://drive.google.com/uc?id=1K7mgdzdQwOERoyft95eFg1-5Tj4XcMAc\n",
            "To: /content/freagan.pkl\n",
            "382MB [00:03, 110MB/s]\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4DWRv9BWTr4A"
      },
      "source": [
        "## Upload an audio file\n",
        "\n",
        "I recommend uploading something simple to start with (think a single instrument or track with silence in it). The file should be in .mp3 or .wav format."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "DPIf-xU-TxdN",
        "colab": {
          "resources": {
            "http://localhost:8080/nbextensions/google.colab/files.js": {
              "data": "Ly8gQ29weXJpZ2h0IDIwMTcgR29vZ2xlIExMQwovLwovLyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKLy8geW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLgovLyBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKLy8KLy8gICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKLy8KLy8gVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQovLyBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAovLyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KLy8gU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAovLyBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4KCi8qKgogKiBAZmlsZW92ZXJ2aWV3IEhlbHBlcnMgZm9yIGdvb2dsZS5jb2xhYiBQeXRob24gbW9kdWxlLgogKi8KKGZ1bmN0aW9uKHNjb3BlKSB7CmZ1bmN0aW9uIHNwYW4odGV4dCwgc3R5bGVBdHRyaWJ1dGVzID0ge30pIHsKICBjb25zdCBlbGVtZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3BhbicpOwogIGVsZW1lbnQudGV4dENvbnRlbnQgPSB0ZXh0OwogIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKHN0eWxlQXR0cmlidXRlcykpIHsKICAgIGVsZW1lbnQuc3R5bGVba2V5XSA9IHN0eWxlQXR0cmlidXRlc1trZXldOwogIH0KICByZXR1cm4gZWxlbWVudDsKfQoKLy8gTWF4IG51bWJlciBvZiBieXRlcyB3aGljaCB3aWxsIGJlIHVwbG9hZGVkIGF0IGEgdGltZS4KY29uc3QgTUFYX1BBWUxPQURfU0laRSA9IDEwMCAqIDEwMjQ7CgpmdW5jdGlvbiBfdXBsb2FkRmlsZXMoaW5wdXRJZCwgb3V0cHV0SWQpIHsKICBjb25zdCBzdGVwcyA9IHVwbG9hZEZpbGVzU3RlcChpbnB1dElkLCBvdXRwdXRJZCk7CiAgY29uc3Qgb3V0cHV0RWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKG91dHB1dElkKTsKICAvLyBDYWNoZSBzdGVwcyBvbiB0aGUgb3V0cHV0RWxlbWVudCB0byBtYWtlIGl0IGF2YWlsYWJsZSBmb3IgdGhlIG5leHQgY2FsbAogIC8vIHRvIHVwbG9hZEZpbGVzQ29udGludWUgZnJvbSBQeXRob24uCiAgb3V0cHV0RWxlbWVudC5zdGVwcyA9IHN0ZXBzOwoKICByZXR1cm4gX3VwbG9hZEZpbGVzQ29udGludWUob3V0cHV0SWQpOwp9CgovLyBUaGlzIGlzIHJvdWdobHkgYW4gYXN5bmMgZ2VuZXJhdG9yIChub3Qgc3VwcG9ydGVkIGluIHRoZSBicm93c2VyIHlldCksCi8vIHdoZXJlIHRoZXJlIGFyZSBtdWx0aXBsZSBhc3luY2hyb25vdXMgc3RlcHMgYW5kIHRoZSBQeXRob24gc2lkZSBpcyBnb2luZwovLyB0byBwb2xsIGZvciBjb21wbGV0aW9uIG9mIGVhY2ggc3RlcC4KLy8gVGhpcyB1c2VzIGEgUHJvbWlzZSB0byBibG9jayB0aGUgcHl0aG9uIHNpZGUgb24gY29tcGxldGlvbiBvZiBlYWNoIHN0ZXAsCi8vIHRoZW4gcGFzc2VzIHRoZSByZXN1bHQgb2YgdGhlIHByZXZpb3VzIHN0ZXAgYXMgdGhlIGlucHV0IHRvIHRoZSBuZXh0IHN0ZXAuCmZ1bmN0aW9uIF91cGxvYWRGaWxlc0NvbnRpbnVlKG91dHB1dElkKSB7CiAgY29uc3Qgb3V0cHV0RWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKG91dHB1dElkKTsKICBjb25zdCBzdGVwcyA9IG91dHB1dEVsZW1lbnQuc3RlcHM7CgogIGNvbnN0IG5leHQgPSBzdGVwcy5uZXh0KG91dHB1dEVsZW1lbnQubGFzdFByb21pc2VWYWx1ZSk7CiAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShuZXh0LnZhbHVlLnByb21pc2UpLnRoZW4oKHZhbHVlKSA9PiB7CiAgICAvLyBDYWNoZSB0aGUgbGFzdCBwcm9taXNlIHZhbHVlIHRvIG1ha2UgaXQgYXZhaWxhYmxlIHRvIHRoZSBuZXh0CiAgICAvLyBzdGVwIG9mIHRoZSBnZW5lcmF0b3IuCiAgICBvdXRwdXRFbGVtZW50Lmxhc3RQcm9taXNlVmFsdWUgPSB2YWx1ZTsKICAgIHJldHVybiBuZXh0LnZhbHVlLnJlc3BvbnNlOwogIH0pOwp9CgovKioKICogR2VuZXJhdG9yIGZ1bmN0aW9uIHdoaWNoIGlzIGNhbGxlZCBiZXR3ZWVuIGVhY2ggYXN5bmMgc3RlcCBvZiB0aGUgdXBsb2FkCiAqIHByb2Nlc3MuCiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dElkIEVsZW1lbnQgSUQgb2YgdGhlIGlucHV0IGZpbGUgcGlja2VyIGVsZW1lbnQuCiAqIEBwYXJhbSB7c3RyaW5nfSBvdXRwdXRJZCBFbGVtZW50IElEIG9mIHRoZSBvdXRwdXQgZGlzcGxheS4KICogQHJldHVybiB7IUl0ZXJhYmxlPCFPYmplY3Q+fSBJdGVyYWJsZSBvZiBuZXh0IHN0ZXBzLgogKi8KZnVuY3Rpb24qIHVwbG9hZEZpbGVzU3RlcChpbnB1dElkLCBvdXRwdXRJZCkgewogIGNvbnN0IGlucHV0RWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGlucHV0SWQpOwogIGlucHV0RWxlbWVudC5kaXNhYmxlZCA9IGZhbHNlOwoKICBjb25zdCBvdXRwdXRFbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQob3V0cHV0SWQpOwogIG91dHB1dEVsZW1lbnQuaW5uZXJIVE1MID0gJyc7CgogIGNvbnN0IHBpY2tlZFByb21pc2UgPSBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gewogICAgaW5wdXRFbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2NoYW5nZScsIChlKSA9PiB7CiAgICAgIHJlc29sdmUoZS50YXJnZXQuZmlsZXMpOwogICAgfSk7CiAgfSk7CgogIGNvbnN0IGNhbmNlbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2J1dHRvbicpOwogIGlucHV0RWxlbWVudC5wYXJlbnRFbGVtZW50LmFwcGVuZENoaWxkKGNhbmNlbCk7CiAgY2FuY2VsLnRleHRDb250ZW50ID0gJ0NhbmNlbCB1cGxvYWQnOwogIGNvbnN0IGNhbmNlbFByb21pc2UgPSBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gewogICAgY2FuY2VsLm9uY2xpY2sgPSAoKSA9PiB7CiAgICAgIHJlc29sdmUobnVsbCk7CiAgICB9OwogIH0pOwoKICAvLyBXYWl0IGZvciB0aGUgdXNlciB0byBwaWNrIHRoZSBmaWxlcy4KICBjb25zdCBmaWxlcyA9IHlpZWxkIHsKICAgIHByb21pc2U6IFByb21pc2UucmFjZShbcGlja2VkUHJvbWlzZSwgY2FuY2VsUHJvbWlzZV0pLAogICAgcmVzcG9uc2U6IHsKICAgICAgYWN0aW9uOiAnc3RhcnRpbmcnLAogICAgfQogIH07CgogIGNhbmNlbC5yZW1vdmUoKTsKCiAgLy8gRGlzYWJsZSB0aGUgaW5wdXQgZWxlbWVudCBzaW5jZSBmdXJ0aGVyIHBpY2tzIGFyZSBub3QgYWxsb3dlZC4KICBpbnB1dEVsZW1lbnQuZGlzYWJsZWQgPSB0cnVlOwoKICBpZiAoIWZpbGVzKSB7CiAgICByZXR1cm4gewogICAgICByZXNwb25zZTogewogICAgICAgIGFjdGlvbjogJ2NvbXBsZXRlJywKICAgICAgfQogICAgfTsKICB9CgogIGZvciAoY29uc3QgZmlsZSBvZiBmaWxlcykgewogICAgY29uc3QgbGkgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdsaScpOwogICAgbGkuYXBwZW5kKHNwYW4oZmlsZS5uYW1lLCB7Zm9udFdlaWdodDogJ2JvbGQnfSkpOwogICAgbGkuYXBwZW5kKHNwYW4oCiAgICAgICAgYCgke2ZpbGUudHlwZSB8fCAnbi9hJ30pIC0gJHtmaWxlLnNpemV9IGJ5dGVzLCBgICsKICAgICAgICBgbGFzdCBtb2RpZmllZDogJHsKICAgICAgICAgICAgZmlsZS5sYXN0TW9kaWZpZWREYXRlID8gZmlsZS5sYXN0TW9kaWZpZWREYXRlLnRvTG9jYWxlRGF0ZVN0cmluZygpIDoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ24vYSd9IC0gYCkpOwogICAgY29uc3QgcGVyY2VudCA9IHNwYW4oJzAlIGRvbmUnKTsKICAgIGxpLmFwcGVuZENoaWxkKHBlcmNlbnQpOwoKICAgIG91dHB1dEVsZW1lbnQuYXBwZW5kQ2hpbGQobGkpOwoKICAgIGNvbnN0IGZpbGVEYXRhUHJvbWlzZSA9IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7CiAgICAgIGNvbnN0IHJlYWRlciA9IG5ldyBGaWxlUmVhZGVyKCk7CiAgICAgIHJlYWRlci5vbmxvYWQgPSAoZSkgPT4gewogICAgICAgIHJlc29sdmUoZS50YXJnZXQucmVzdWx0KTsKICAgICAgfTsKICAgICAgcmVhZGVyLnJlYWRBc0FycmF5QnVmZmVyKGZpbGUpOwogICAgfSk7CiAgICAvLyBXYWl0IGZvciB0aGUgZGF0YSB0byBiZSByZWFkeS4KICAgIGxldCBmaWxlRGF0YSA9IHlpZWxkIHsKICAgICAgcHJvbWlzZTogZmlsZURhdGFQcm9taXNlLAogICAgICByZXNwb25zZTogewogICAgICAgIGFjdGlvbjogJ2NvbnRpbnVlJywKICAgICAgfQogICAgfTsKCiAgICAvLyBVc2UgYSBjaHVua2VkIHNlbmRpbmcgdG8gYXZvaWQgbWVzc2FnZSBzaXplIGxpbWl0cy4gU2VlIGIvNjIxMTU2NjAuCiAgICBsZXQgcG9zaXRpb24gPSAwOwogICAgd2hpbGUgKHBvc2l0aW9uIDwgZmlsZURhdGEuYnl0ZUxlbmd0aCkgewogICAgICBjb25zdCBsZW5ndGggPSBNYXRoLm1pbihmaWxlRGF0YS5ieXRlTGVuZ3RoIC0gcG9zaXRpb24sIE1BWF9QQVlMT0FEX1NJWkUpOwogICAgICBjb25zdCBjaHVuayA9IG5ldyBVaW50OEFycmF5KGZpbGVEYXRhLCBwb3NpdGlvbiwgbGVuZ3RoKTsKICAgICAgcG9zaXRpb24gKz0gbGVuZ3RoOwoKICAgICAgY29uc3QgYmFzZTY0ID0gYnRvYShTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KG51bGwsIGNodW5rKSk7CiAgICAgIHlpZWxkIHsKICAgICAgICByZXNwb25zZTogewogICAgICAgICAgYWN0aW9uOiAnYXBwZW5kJywKICAgICAgICAgIGZpbGU6IGZpbGUubmFtZSwKICAgICAgICAgIGRhdGE6IGJhc2U2NCwKICAgICAgICB9LAogICAgICB9OwogICAgICBwZXJjZW50LnRleHRDb250ZW50ID0KICAgICAgICAgIGAke01hdGgucm91bmQoKHBvc2l0aW9uIC8gZmlsZURhdGEuYnl0ZUxlbmd0aCkgKiAxMDApfSUgZG9uZWA7CiAgICB9CiAgfQoKICAvLyBBbGwgZG9uZS4KICB5aWVsZCB7CiAgICByZXNwb25zZTogewogICAgICBhY3Rpb246ICdjb21wbGV0ZScsCiAgICB9CiAgfTsKfQoKc2NvcGUuZ29vZ2xlID0gc2NvcGUuZ29vZ2xlIHx8IHt9OwpzY29wZS5nb29nbGUuY29sYWIgPSBzY29wZS5nb29nbGUuY29sYWIgfHwge307CnNjb3BlLmdvb2dsZS5jb2xhYi5fZmlsZXMgPSB7CiAgX3VwbG9hZEZpbGVzLAogIF91cGxvYWRGaWxlc0NvbnRpbnVlLAp9Owp9KShzZWxmKTsK",
              "ok": true,
              "headers": [
                [
                  "content-type",
                  "application/javascript"
                ]
              ],
              "status": 200,
              "status_text": ""
            }
          },
          "base_uri": "https://localhost:8080/",
          "height": 72
        },
        "outputId": "87bf15c0-f392-4ff2-db8a-9c05647b50e2"
      },
      "source": [
        "from google.colab import files\n",
        "\n",
        "uploaded = files.upload()\n",
        "\n",
        "# for fn in uploaded.keys():\n",
        "#   print('User uploaded file \"{name}\" with length {length} bytes'.format(\n",
        "#       name=fn, length=len(uploaded[fn])))"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "text/html": [
              "\n",
              "     <input type=\"file\" id=\"files-424fbdaa-f0ed-475e-8329-ee8da070d429\" name=\"files[]\" multiple disabled\n",
              "        style=\"border:none\" />\n",
              "     <output id=\"result-424fbdaa-f0ed-475e-8329-ee8da070d429\">\n",
              "      Upload widget is only available when the cell has been executed in the\n",
              "      current browser session. Please rerun this cell to enable.\n",
              "      </output>\n",
              "      <script src=\"/nbextensions/google.colab/files.js\"></script> "
            ],
            "text/plain": [
              "<IPython.core.display.HTML object>"
            ]
          },
          "metadata": {
            "tags": []
          }
        },
        {
          "output_type": "stream",
          "text": [
            "Saving rushing-back-clip.wav to rushing-back-clip.wav\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1JXB3HnLjP-j"
      },
      "source": [
        "##Process audio\n",
        "The next step process our audio files. Edit the first line of the next cell to point to your audio file. The run the cell after that to process the audio and generate a graph of the volume data."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "i8TWpZNjTwWa"
      },
      "source": [
        "# make sure you are pointing to your audio file\n",
        "wav_filename = '/content/test.wav'\n",
        "# set th framerat for your video output\n",
        "fps = 24\n"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PhswH3EwngCU"
      },
      "source": [
        "Run this cell to process the audio file (you don’t need to edit anything)."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "tMKDAPieT7XE",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 227
        },
        "outputId": "e87bacaa-1372-4780-9682-25ea2ccf772c"
      },
      "source": [
        "import os\n",
        "import numpy as np\n",
        "from scipy.interpolate import interp1d\n",
        "from scipy.io import wavfile\n",
        "import matplotlib.pyplot as plt\n",
        "import PIL.Image\n",
        "import moviepy.editor\n",
        "\n",
        "# import dnnlib\n",
        "# import dnnlib.tflib as tflib\n",
        "# import pickle\n",
        "# import pretrained_networks\n",
        "\n",
        "audio = {}\n",
        "\n",
        "if not os.path.exists(wav_filename):\n",
        "    audio_clip = moviepy.editor.AudioFileClip(wav_filename)\n",
        "    audio_clip.write_audiofile(wav_filename, fps=44100, nbytes=2, codec='pcm_s16le')\n",
        "track_name = os.path.basename(wav_filename)[:-4]\n",
        "rate, signal = wavfile.read(wav_filename)\n",
        "signal = np.mean(signal, axis=1) # to mono\n",
        "signal = np.abs(signal)\n",
        "# seed = signal.shape[0]\n",
        "duration = signal.shape[0] / rate\n",
        "frames = int(np.ceil(duration * fps))\n",
        "samples_per_frame = signal.shape[0] / frames\n",
        "audio[track_name] = np.zeros(frames, dtype=signal.dtype)\n",
        "for frame in range(frames):\n",
        "    start = int(round(frame * samples_per_frame))\n",
        "    stop = int(round((frame + 1) * samples_per_frame))\n",
        "    audio[track_name][frame] = np.mean(signal[start:stop], axis=0)\n",
        "audio[track_name] /= max(audio[track_name])\n",
        "\n",
        "for track in sorted(audio.keys()):\n",
        "    plt.figure(figsize=(8, 3))\n",
        "    plt.title(track)\n",
        "    plt.plot(audio[track])\n",
        "    plt.savefig(f'../{track}.png')"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "<Figure size 576x216 with 1 Axes>"
            ]
          },
          "metadata": {
            "tags": [],
            "needs_background": "light"
          }
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ONTlyw6ZUNQl"
      },
      "source": [
        "Run the next cell to define some functions we’ll need to use to generate our inference images."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "KyCHTNpzPuWL"
      },
      "source": [
        "import dnnlib\n",
        "import numpy as np\n",
        "import torch\n",
        "import PIL.Image\n",
        "import legacy\n",
        "\n",
        "\n",
        "def line_interpolate(zs, steps, easing):\n",
        "    out = []\n",
        "    for i in range(len(zs)-1):\n",
        "        for index in range(steps):\n",
        "            t = index/float(steps)\n",
        "\n",
        "            if(easing == 'linear'):\n",
        "                out.append(zs[i+1]*t + zs[i]*(1-t))\n",
        "            elif (easing == 'easeInOutQuad'):\n",
        "                if(t < 0.5):\n",
        "                    fr = 2 * t * t\n",
        "                else:\n",
        "                    fr = (-2 * t * t) + (4 * t) - 1\n",
        "                out.append(zs[i+1]*fr + zs[i]*(1-fr))\n",
        "            elif (easing == 'bounceEaseOut'):\n",
        "                if (t < 4/11):\n",
        "                    fr = 121 * t * t / 16\n",
        "                elif (t < 8/11):\n",
        "                    fr = (363 / 40.0 * t * t) - (99 / 10.0 * t) + 17 / 5.0\n",
        "                elif t < 9/ 0:\n",
        "                    fr = (4356 / 361.0 * t * t) - (35442 / 1805.0 * t) + 16061 / 1805.0\n",
        "                else:\n",
        "                    fr = (54 / 5.0 * t * t) - (513 / 25.0 * t) + 268 / 25.0\n",
        "                out.append(zs[i+1]*fr + zs[i]*(1-fr))\n",
        "            elif (easing == 'circularEaseOut'):\n",
        "                fr = np.sqrt((2 - t) * t)\n",
        "                out.append(zs[i+1]*fr + zs[i]*(1-fr))\n",
        "            elif (easing == 'circularEaseOut2'):\n",
        "                fr = np.sqrt(np.sqrt((2 - t) * t))\n",
        "                out.append(zs[i+1]*fr + zs[i]*(1-fr))\n",
        "    return out\n",
        "\n",
        "\n",
        "def images(G,device,inputs,space,truncation_psi,label,noise_mode,outdir,start=None,stop=None):\n",
        "    if(start is not None and stop is not None):\n",
        "        tp = start\n",
        "        tp_i = (stop-start)/len(inputs)\n",
        "\n",
        "    for idx, i in enumerate(inputs):\n",
        "        print('Generating image for frame %d/%d ...' % (idx, len(inputs)))\n",
        "        \n",
        "        if (space=='z'):\n",
        "            z = torch.from_numpy(i).to(device)\n",
        "            if(start is not None and stop is not None):\n",
        "                img = G(z, label, truncation_psi=tp, noise_mode=noise_mode)\n",
        "                tp = tp+tp_i\n",
        "            else:\n",
        "                img = G(z, label, truncation_psi=truncation_psi, noise_mode=noise_mode)\n",
        "        else:\n",
        "            if i.shape[0] == 18: \n",
        "              i = torch.from_numpy(i).unsqueeze(0).to(device)\n",
        "            img = G.synthesis(i, noise_mode=noise_mode, force_fp32=True)\n",
        "        img = (img.permute(0, 2, 3, 1) * 127.5 + 128).clamp(0, 255).to(torch.uint8)\n",
        "        PIL.Image.fromarray(img[0].cpu().numpy(), 'RGB').save(f'{outdir}/frame{idx:04d}.png')\n",
        "\n",
        "# def lerp(v0, v1, t):\n",
        "#     # print(t)\n",
        "#     return v1*t + v0*(1-t)\n",
        "    \n",
        "\n",
        "def seeds_to_zs(G,seeds):\n",
        "    zs = []\n",
        "    for seed_idx, seed in enumerate(seeds):\n",
        "        z = np.random.RandomState(seed).randn(1, G.z_dim)\n",
        "        zs.append(z)\n",
        "    return zs\n",
        "\n",
        "def valmap(value, istart, istop, ostart, ostop):\n",
        "    return ostart + (ostop - ostart) * ((value - istart) / (istop - istart))\n",
        "\n",
        "def zs_to_ws(G,device,label,truncation_psi,zs):\n",
        "    ws = []\n",
        "    for z_idx, z in enumerate(zs):\n",
        "        z = torch.from_numpy(z).to(device)\n",
        "        w = G.mapping(z, label, truncation_psi=truncation_psi, truncation_cutoff=8)\n",
        "        ws.append(w)\n",
        "    return ws"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kByt3G4yUp02"
      },
      "source": [
        "## Generate Images\n",
        "\n",
        "### Use Volume to interpolate between two seeds\n",
        "The next cell will take two seed values and do a linear interpolation of them using the volume from your audio. When the audio is silent, it will be the first seed you list. When it is at its loudest it will be the second. Everything in between will be an interpolated value."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "VSPddCx9iVSR"
      },
      "source": [
        "# set each of these variables\n",
        "network_pkl = '/content/freagan.pkl'\n",
        "seeds=[38,11]\n",
        "truncation_psi = 0.5\n",
        "outdir = '/content/out/'\n",
        "\n",
        "# ---------------------------\n",
        "#you probably won't need to edit anything below this\n",
        "# ---------------------------\n",
        "print('Loading networks from \"%s\"...' % network_pkl)\n",
        "device = torch.device('cuda')\n",
        "with dnnlib.util.open_url(network_pkl) as f:\n",
        "    G = legacy.load_network_pkl(f)['G_ema'].to(device) # type: ignore\n",
        "\n",
        "os.makedirs(outdir, exist_ok=True)\n",
        "\n",
        "label = torch.zeros([1, G.c_dim], device=device)\n",
        "\n",
        "\n",
        "def lerp(v0, v1, t):\n",
        "    # print(t)\n",
        "    return v0*(1.0-t)+v1*t\n",
        "\n",
        "\n",
        "ends = seeds_to_zs(G,seeds)\n",
        "ends_w = zs_to_ws(G,device,label,truncation_psi,ends)\n",
        "\n",
        "vectors = []\n",
        "for f in range(frames):\n",
        "  vectors.append(lerp(ends_w[0],ends_w[1],audio[track_name][f]))\n",
        "\n",
        "#generate_images_in_w_space(vectors,truncation_value)\n",
        "\n",
        "images(G,device,vectors,'w',truncation_psi,label,'const',outdir,start=None,stop=None)\n"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "tOkh2DZpV-9W"
      },
      "source": [
        "### Combine the frames into a video and add the audio track back to it\n",
        "\n",
        "There’s probably a cleaner way to do this all in moviepy but I’m being lazy."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "dPClSNx_Atn-"
      },
      "source": [
        "!ffmpeg -r {fps} -i {outdir}frame%04d.png -vcodec libx264 -pix_fmt yuv420p /content/out.mp4"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "R7TUwqrTi4y-"
      },
      "source": [
        "mp4_filename = '/content/combined.mp4'\n",
        "# video_clip = moviepy.editor.VideoClip(render_frame, duration=duration)\n",
        "video_clip = moviepy.editor.VideoFileClip('/content/out.mp4')\n",
        "audio_clip_i = moviepy.editor.AudioFileClip(wav_filename)\n",
        "video_clip = video_clip.set_audio(audio_clip_i)\n",
        "video_clip.write_videofile(mp4_filename, fps=fps, codec='libx264', audio_codec='aac', bitrate='15M')"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xCjfK_ItjJDb"
      },
      "source": [
        "## Pitch Control\n",
        "\n",
        "The above video processes volume, but maybe we want to process pitch change?\n",
        "\n",
        "For this to work correctly I highly recommend you use an audio sample of a single instrument (singing, piano, flute, etc.). Polyphonic sound tends to confuse this model."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "H9aCVCJ8jRuD"
      },
      "source": [
        "!pip install crepe"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LDcvKdaRoSfW"
      },
      "source": [
        "Uncomment and edit these lines only if you want to change the settings from your previous video. Otherwise it will use the settings from earlier cells."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "zBtAB5g4oRxP"
      },
      "source": [
        "# wav_filename = '/content/test.wav'\n",
        "# fps = 24\n",
        "# network_pkl = '/content/freagan.pkl'\n",
        "# seeds=[38,11]\n",
        "# truncation_psi = 0.5\n",
        "outdir = '/content/out-pitch/'"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Pfb5tHG7olnf"
      },
      "source": [
        "Now, run each cell in order to produce a linear interpolation between two points according to pitch from your audio file."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "HI5usILyjkM9"
      },
      "source": [
        "import crepe\n",
        "from scipy.io import wavfile\n",
        "\n",
        "sr, audio_w = wavfile.read(wav_filename)\n",
        "time, frequency, confidence, activation = crepe.predict(audio_w, sr, viterbi=False,step_size=40)"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Mr6kqGWKjutu"
      },
      "source": [
        "def mapped(x):\n",
        "  val = (x-minf)/(maxf-minf)\n",
        "  return (val*(mapmax-mapmin))+mapmin\n",
        "\n",
        "minf = min(frequency)\n",
        "maxf = max(frequency)\n",
        "mapmin = 0.0\n",
        "mapmax = 1.0\n",
        "\n",
        "for t in np.arange(len(time)):\n",
        "  print(mapped(frequency[t]))"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "HvdmS30NpWCB"
      },
      "source": [
        "plt.plot(audio[track])\n",
        "plt.plot(frequency,'g')\n",
        "plt.show()"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "kJXtRjfVkGBQ"
      },
      "source": [
        "vectors = []\n",
        "for f in range(frames):\n",
        "  vectors.append(lerp(ends_w[0],ends_w[1],mapped(frequency[f])))\n",
        "\n",
        "os.makedirs(outdir, exist_ok=True)\n",
        "images(G,device,vectors,'w',truncation_psi,label,'const',outdir,start=None,stop=None)"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Vq-n0aHTSo76"
      },
      "source": [
        "!ffmpeg -r {fps} -i {outdir}frame%04d.png -vcodec libx264 -pix_fmt yuv420p /content/out-pitch.mp4\n",
        "mp4_filename = '/content/combined-pitch.mp4'\n",
        "# video_clip = moviepy.editor.VideoClip(render_frame, duration=duration)\n",
        "video_clip = moviepy.editor.VideoFileClip('/content/out-pitch.mp4')\n",
        "audio_clip_i = moviepy.editor.AudioFileClip(wav_filename)\n",
        "video_clip = video_clip.set_audio(audio_clip_i)\n",
        "video_clip.write_videofile(mp4_filename, fps=fps, codec='libx264', audio_codec='aac', bitrate='15M')"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "30Z-gYgfmPAR"
      },
      "source": [
        "<h1><font color='red'>Stop!</font></h1>\n",
        "\n",
        "# Nothing past here works (yet!)\n",
        "\n",
        "I’ll come back to this in the next week or two, promise."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ibDI8hGWWPD0"
      },
      "source": [
        "## Use Volume to control truncation\n",
        "In this example, we’ll use almost the same technique but use volume to change the truncation value. \n",
        "\n",
        "It’s helpful that both interpolation and truncation are essentially 0.0 to 1.0. This matches the volume signal’s output, but what if we wanted to alter it?"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "X2LpM3o05no6"
      },
      "source": [
        "def mapped(x):\n",
        "  val = (x-minf)/(maxf-minf)\n",
        "  return (val*(mapmax-mapmin))+mapmin\n",
        "\n",
        "# minf = min(frequency)\n",
        "# maxf = max(frequency)\n",
        "minf = 0.0\n",
        "maxf = 1.0\n",
        "print(minf,maxf)\n",
        "mapmin = 0.4\n",
        "mapmax = 0.8\n",
        "\n",
        "# for t in np.arange(len(time)):\n",
        "#   print(mapped(frequency[t]))\n",
        "\n",
        "print(len(audio[track_name]))\n",
        "\n",
        "for f in range(frames):\n",
        "  print(mapped(audio[track_name][f]))"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "ifbLsbOcXsgy"
      },
      "source": [
        "seeds=[10]\n",
        "\n",
        "#you probably won't need to edit anything below this\n",
        "tflib.init_tf()\n",
        "print('Loading networks from \"%s\"...' % network_pkl)\n",
        "with dnnlib.util.open_url(network_pkl) as fp:\n",
        "    _G, _D, Gs = pickle.load(fp)\n",
        "\n",
        "Gs_kwargs = {\n",
        "    'output_transform': dict(func=tflib.convert_images_to_uint8, nchw_to_nhwc=True),\n",
        "    'randomize_noise': False\n",
        "}\n",
        "if truncation_psi is not None:\n",
        "    Gs_kwargs['truncation_psi'] = truncation_psi\n",
        "Gs_syn_kwargs = Gs_kwargs\n",
        "Gs_syn_kwargs['minibatch_size'] = 4\n",
        "noise_vars = [var for name, var in Gs.components.synthesis.vars.items() if name.startswith('noise')]\n",
        "w_avg = Gs.get_var('dlatent_avg')\n",
        "\n",
        "seed_z = generate_zs_from_seeds(seeds,Gs)\n",
        "\n",
        "rnd = np.random.RandomState(seeds[0])\n",
        "\n",
        "temp_dir = '%s-trunc_frames%06d'%(track_name,int(1000000*random.random()))\n",
        "os.system('mkdir %s'%temp_dir)\n",
        "\n",
        "for f in range(frames):\n",
        "  print('Rendering frame %d/%d ...' % (f,frames))\n",
        "\n",
        "  #edit the next line to alter the volume signal\n",
        "  # Gs_kwargs.truncation_psi = audio[track_name][f]*2 #multiply by 2 (0.0 to 2.0 for volume signal/truncation value now)\n",
        "  Gs_kwargs.truncation_psi = (audio[track_name][f]-0.5)*2 #(-1.0 to 1.0 for volume signal/truncation value now)\n",
        "\n",
        "  tflib.set_vars({var: rnd.randn(*var.shape.as_list()) for var in noise_vars}) # [height, width]\n",
        "  images = Gs.run(seed_z[0], None, **Gs_kwargs) # [minibatch, height, width, channel]\n",
        "  PIL.Image.fromarray(images[0], 'RGB').save('%s/frame%05d.png' % (temp_dir,f))"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "gw3negi0e7ll"
      },
      "source": [
        "!ffmpeg -r 12 -i /content/stylegan2/bass-trunc_frames844699/frame%05d.png -vcodec libx264 -pix_fmt yuv420p /content/bass-truncation-volume.mp4"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "g1AC2mF1bwKP",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 170
        },
        "outputId": "38b8c4b9-32b0-4e42-c352-4eea813eb9d6"
      },
      "source": [
        "mp4_filename = '../volume-trunc-test-all.mp4'\n",
        "# video_clip = moviepy.editor.VideoClip(render_frame, duration=duration)\n",
        "video_clip = moviepy.editor.VideoFileClip('/content/bass-truncation-volume.mp4')\n",
        "audio_clip_i = moviepy.editor.AudioFileClip('/content/AI.mp3')\n",
        "video_clip = video_clip.set_audio(audio_clip_i)\n",
        "video_clip.write_videofile(mp4_filename, fps=fps, codec='libx264', audio_codec='aac', bitrate='8M')"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "[MoviePy] >>>> Building video ../volume-trunc-test-all.mp4\n",
            "[MoviePy] Writing audio in volume-trunc-test-allTEMP_MPY_wvf_snd.mp4\n"
          ],
          "name": "stdout"
        },
        {
          "output_type": "stream",
          "text": [
            "100%|██████████| 1008/1008 [00:01<00:00, 622.07it/s]"
          ],
          "name": "stderr"
        },
        {
          "output_type": "stream",
          "text": [
            "[MoviePy] Done.\n",
            "[MoviePy] Writing video ../volume-trunc-test-all.mp4\n"
          ],
          "name": "stdout"
        },
        {
          "output_type": "stream",
          "text": [
            "\n",
            "100%|█████████▉| 549/550 [00:38<00:00, 14.21it/s]\n"
          ],
          "name": "stderr"
        },
        {
          "output_type": "stream",
          "text": [
            "[MoviePy] Done.\n",
            "[MoviePy] >>>> Video ready: ../volume-trunc-test-all.mp4 \n",
            "\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "N_78NFCdqL68"
      },
      "source": [
        "## Using feature vectors\n",
        "\n",
        "Let’s look at an example using a feature vector. In this case we’ll just use the straight audio signal.\n",
        "\n",
        "Upload your feature vector to Colab and then reference it’s location with a variable."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Kl5w7TaLxldW",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 51
        },
        "outputId": "8328616c-95ef-4a20-cb35-7ba5c9e7baf6"
      },
      "source": [
        "network_pkl = \"/content/ffhq.pkl\"\n",
        "\n",
        "tflib.init_tf()\n",
        "print('Loading networks from \"%s\"...' % network_pkl)\n",
        "with dnnlib.util.open_url(network_pkl) as fp:\n",
        "    _G, _D, Gs = pickle.load(fp)\n",
        "\n",
        "Gs_kwargs = {\n",
        "    'output_transform': dict(func=tflib.convert_images_to_uint8, nchw_to_nhwc=True),\n",
        "    'randomize_noise': False\n",
        "}\n",
        "if truncation_psi is not None:\n",
        "    Gs_kwargs['truncation_psi'] = truncation_psi\n",
        "Gs_syn_kwargs = Gs_kwargs\n",
        "Gs_syn_kwargs['minibatch_size'] = 4\n",
        "noise_vars = [var for name, var in Gs.components.synthesis.vars.items() if name.startswith('noise')]\n",
        "w_avg = Gs.get_var('dlatent_avg')\n",
        "\n",
        "def generate_mov(seed, truncation, direction_vec, scale, n_frames, out_name = 'out', noise_spec = None, loop=True):\n",
        "  \"\"\"Generates a mov moving back and forth along the chosen direction vector\"\"\"\n",
        "  # Example of reading a generated set of images, and storing as MP4.\n",
        "  %mkdir out\n",
        "  movieName = f'out/{out_name}.mp4'\n",
        "  offset = -10\n",
        "  step = 20 / n_frames\n",
        "  imgs = []\n",
        "  for i in range(n_frames):\n",
        "    print(f'{i} / {n_frames}')\n",
        "    \n",
        "    \n",
        "    batch_size = 1\n",
        "    all_seeds = [seed] * batch_size\n",
        "    all_z = np.stack([np.random.RandomState(seed).randn(*Gs.input_shape[1:]) for seed in all_seeds]) # [minibatch, component]\n",
        "    all_w = Gs.components.mapping.run(all_z, None) # [minibatch, layer, component]\n",
        "    if truncation != 1:\n",
        "        w_avg = Gs.get_var('dlatent_avg')\n",
        "        all_w = w_avg + (all_w - w_avg) * truncation # [minibatch, layer, component]\n",
        "    all_w += direction_vec * offset * scale\n",
        "    all_images = Gs.components.synthesis.run(all_w, **Gs_syn_kwargs)\n",
        "    #save image and display\n",
        "    final_im = PIL.Image.fromarray(np.median(all_images, axis=0).astype(np.uint8))\n",
        "    imgs.append(final_im)\n",
        "    #increase offset\n",
        "    offset += step\n",
        "  if loop:\n",
        "    imgs += imgs[::-1]\n",
        "  with imageio.get_writer(movieName, mode='I') as writer:\n",
        "    for image in log_progress(list(imgs), name = \"Creating animation\"):\n",
        "        writer.append_data(np.array(image))"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Setting up TensorFlow plugin \"fused_bias_act.cu\": Preprocessing... Compiling... Loading... Done.\n",
            "Setting up TensorFlow plugin \"upfirdn_2d.cu\": Preprocessing... Compiling... Loading... Done.\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "PA40ehfqy2S2"
      },
      "source": [
        "seed = 10 # starting seed (will appear at 0.5)\n",
        "truncation = 0.7\n",
        "feature = '/content/profile-c2.npy'\n",
        "feature_range = 2 # feature_range maps the range of change in features \n",
        "scale = 1 # scale multiples the strength of the feature (1 is prob fine)\n",
        "\n",
        "#-------------------\n",
        "\n",
        "tflib.init_tf()\n",
        "print('Loading networks from \"%s\"...' % network_pkl)\n",
        "with dnnlib.util.open_url(network_pkl) as fp:\n",
        "    _G, _D, Gs = pickle.load(fp)\n",
        "\n",
        "Gs_kwargs = {\n",
        "    'output_transform': dict(func=tflib.convert_images_to_uint8, nchw_to_nhwc=True),\n",
        "    'randomize_noise': False\n",
        "}\n",
        "if truncation_psi is not None:\n",
        "    Gs_kwargs['truncation_psi'] = truncation_psi\n",
        "Gs_syn_kwargs = Gs_kwargs\n",
        "Gs_syn_kwargs['minibatch_size'] = 4\n",
        "noise_vars = [var for name, var in Gs.components.synthesis.vars.items() if name.startswith('noise')]\n",
        "w_avg = Gs.get_var('dlatent_avg')\n",
        "\n",
        "# get starting z and w\n",
        "rnd = np.random.RandomState(seed)\n",
        "z = rnd.randn(1, *Gs.input_shape[1:])\n",
        "w = Gs.components.mapping.run(z, None)\n",
        "\n",
        "# make dir\n",
        "feature_name=os.path.basename(feature)[:-4] \n",
        "dir = '%s_%s_range%02d_seed%05d'%(track_name,feature_name,feature_range,seed)\n",
        "os.system('mkdir %s'%dir)\n",
        "\n",
        "# setup\n",
        "feature_vec = np.load(feature)\n",
        "min_range = -feature_range\n",
        "max_range = feature_range\n",
        "offset = min_range #start value\n",
        "\n",
        "#generate frames\n",
        "for f in range(frames):\n",
        "  print('Rendering frame %d/%d ...' % (f,frames))\n",
        "\n",
        "  if truncation != 1:\n",
        "    w = w_avg + (w - w_avg) * truncation # [minibatch, layer, component]\n",
        "  \n",
        "  w += feature_vec * offset * scale\n",
        "\n",
        "  #save image and display\n",
        "  image = Gs.components.synthesis.run(w, **Gs_syn_kwargs)\n",
        "  PIL.Image.fromarray(image[0],'RGB').save('%s/frame%05d.png' % (dir,f))\n",
        "  \n",
        "  #increase offset\n",
        "  offset = lerp( min_range,max_range,audio[track_name][f] )\n",
        "\n",
        "  "
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Hbk-mwtQ2oWj"
      },
      "source": [
        "!ffmpeg -r 60 -i /content/stylegan2/pleasureisallmine_01-stereo_profile-c2_range02_seed00010/frame%05d.png -vcodec libx264 -pix_fmt yuv420p /content/sound-feature-volume-range2.mp4"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "JnoVg2o0AE3_",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 170
        },
        "outputId": "70604c5d-6f71-4e47-b6df-a87ef1b3906d"
      },
      "source": [
        "mp4_filename = '../volume-feature-test-range2.mp4'\n",
        "# video_clip = moviepy.editor.VideoClip(render_frame, duration=duration)\n",
        "video_clip = moviepy.editor.VideoFileClip('/content/sound-feature-volume-range2.mp4')\n",
        "audio_clip_i = moviepy.editor.AudioFileClip('/content/stylegan2/pleasureisallmine_01-stereo.wav')\n",
        "video_clip = video_clip.set_audio(audio_clip_i)\n",
        "video_clip.write_videofile(mp4_filename, fps=fps, codec='libx264', audio_codec='aac', bitrate='8M')"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "[MoviePy] >>>> Building video ../volume-feature-test-range2.mp4\n",
            "[MoviePy] Writing audio in volume-feature-test-range2TEMP_MPY_wvf_snd.mp4\n"
          ],
          "name": "stdout"
        },
        {
          "output_type": "stream",
          "text": [
            "100%|██████████| 128/128 [00:00<00:00, 640.23it/s]"
          ],
          "name": "stderr"
        },
        {
          "output_type": "stream",
          "text": [
            "[MoviePy] Done.\n",
            "[MoviePy] Writing video ../volume-feature-test-range2.mp4\n"
          ],
          "name": "stdout"
        },
        {
          "output_type": "stream",
          "text": [
            "\n",
            "100%|██████████| 347/347 [00:15<00:00, 22.54it/s]\n"
          ],
          "name": "stderr"
        },
        {
          "output_type": "stream",
          "text": [
            "[MoviePy] Done.\n",
            "[MoviePy] >>>> Video ready: ../volume-feature-test-range2.mp4 \n",
            "\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "ZMyuqpcDBqQ3"
      },
      "source": [
        ""
      ],
      "execution_count": null,
      "outputs": []
    }
  ]
}